package com.ruolin.micro.gateway.server.init;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.ruolin.micro.gateway.server.cache.*;
import com.ruolin.micro.gateway.server.constant.DubboMetadataConstant;
import com.ruolin.micro.gateway.server.constant.PropertiesConstant;
import com.ruolin.micro.gateway.server.discovery.ServiceDiscoveryAdapter;
import com.ruolin.micro.gateway.server.listener.RemoteRefreshRouteListener;
import com.ruolin.micro.gateway.server.metadata.*;
import com.ruolin.micro.gateway.server.utils.DubboServiceUtils;
import com.ruolin.micro.gateway.server.utils.GatewayUtils;
import org.apache.dubbo.registry.client.ServiceInstance;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * init dubbo metadata cache
 */

@Component
public class ReferenceBeanCacheInitializingBean implements InitializingBean, EnvironmentAware {
    private Environment environment;
    private final ServiceDiscoveryAdapter serviceDiscoveryAdapter;
    private final ConfigService configService;

    @Autowired
    public ReferenceBeanCacheInitializingBean(final ServiceDiscoveryAdapter serviceDiscoveryAdapter, final ConfigService configService) {
        this.serviceDiscoveryAdapter = serviceDiscoveryAdapter;
        this.configService = configService;
        serviceDiscoveryAdapter.getServices().forEach(s -> {
            List<ServiceInstance> serviceInstances = serviceDiscoveryAdapter.getInstances(s);
            for (ServiceInstance instance : serviceInstances) {
                InstanceMetadata metadata = new InstanceMetadata().convert(instance.getMetadata());
                String dataId = DubboServiceUtils.getDataId(metadata.getInterfaceName(), metadata.getVersion(), metadata.getGroup(), metadata.getApplication());
                try {
                    configService.addListener(dataId, DubboMetadataConstant.METADATA_GROUP, new RemoteRefreshRouteListener());
                } catch (NacosException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void afterPropertiesSet() {
        serviceDiscoveryAdapter.getServices().forEach(s -> {
            List<ServiceInstance> instances = serviceDiscoveryAdapter.getInstances(s);
            if (CollectionUtil.isNotEmpty(instances)) {
                instances.forEach(instance -> {
                    //根据路由匹配Reference
                    ServiceRouteMapping serviceRouteMapping = new ServiceRouteMapping();
                    serviceRouteMapping.buildRouteMapping(instance);
                    String registryAddress = environment.getProperty(PropertiesConstant.REGISTRY);
                    String cluster = environment.getProperty(PropertiesConstant.CLUSTER);
                    InstanceMetadata instanceMetadata = new InstanceMetadata().convert(instance.getMetadata());
                    instanceMetadata.setAddress(registryAddress);
                    instanceMetadata.setGeneric(DubboMetadataConstant.GENERIC_VALUE);
                    instanceMetadata.setCluster(cluster);
                    List<String> routes = serviceRouteMapping.getRoute(instance.getServiceName());
                    ApplicationRouterMetadataCache.getMetadataCache().put(instanceMetadata.getApplication(), GatewayUtils.buildMetadata(instanceMetadata, configService, environment));
                    routes.forEach(r -> {
                        RouteReferenceBeanMappingCache.getBeanMapping().put(r, GatewayUtils.buildReferenceBean(instanceMetadata));
                    });

                    ApplicationGenericServiceCache.getCache().put(instance.getMetadata(DubboMetadataConstant.APPLICATION), GatewayUtils.buildReferenceBean(instanceMetadata));
                });
            }
        });
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
